﻿using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Permissions;
using System.Speech.Recognition;
using System.Speech.Synthesis;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using System.Windows;
using System.Runtime.Intrinsics.X86;
using System.Media;
using static System.Net.Mime.MediaTypeNames;

namespace AudioDemo
{
    /// <summary>
    /// 音频处理类
    /// </summary>
    /// <remarks>基于微软speech的音频识别、音频合成和音频播放</remarks>
    public class AudioHelper
    {
        #region 语音识别相关字段、属性

        /// <summary>
        /// 基于speech的音频处理引擎
        /// </summary>
        private static SpeechRecognitionEngine sre;


        /// <summary>
        /// 正在识别
        /// </summary>
        private bool recognizing = false;


        /// <summary>
        /// 停止指令
        /// </summary>
        private bool stopCMD = false;


        /// <summary>
        /// 识别成功标志
        /// </summary>
        private bool sucessed = false;


        /// <summary>
        /// 开始时间
        /// </summary>
        private DateTime timeStart = DateTime.Now;


        /// <summary>
        /// 关键词序列列表
        /// </summary>
        private static List<List<string>> wordsList = new List<List<string>>();


        /// <summary>
        /// 识别结果列表
        /// </summary>
        private static List<bool[]> resultsList = new List<bool[]>();

        #endregion


        #region 语音识别方法

        /// <summary>
        /// 识别关键字
        /// </summary>
        /// <param name="sequenceWords">关键词序列，必须同时满足的关键词之间用英文逗号分隔，多条可选序列之间用英文斜杠分隔</param>
        /// <param name="timeout">超时设定，秒。默认30s</param>
        public bool RecognizeKeyWords(string sequenceWords, int timeout = 30)
        {
            try
            {
                lock (this)
                {
                    if (recognizing) //正在识别时，取消上个任务，进行新任务
                    {
                        if (sre != null)
                            sre.Dispose();
                        stopCMD = true;

                        DispatcherHelper.DoEvents();        //测试用---------------------------------
                        Thread.Sleep(5000);
                    }
                }

                if (string.IsNullOrEmpty(sequenceWords))
                    return false;

                //参数初始化
                recognizing = true;
                stopCMD = false;
                sucessed = false;
                timeStart = DateTime.Now;
                bool result = false;

                //拆分关键词组
                SplitWords(sequenceWords);

                //初始化引擎
                CultureInfo ci = new CultureInfo("zh-CN");  //简体中文
                sre = new SpeechRecognitionEngine(ci);
                sre.SetInputToDefaultAudioDevice();
                sre.SpeechRecognized += sre_SpeechRecognized;

                foreach (var item in wordsList)
                {
                    Choices choice = new Choices();
                    choice = new Choices();
                    foreach (string str in item)
                        choice.Add(str);
                    GrammarBuilder gb = new GrammarBuilder();
                    gb.Append(choice);
                    Grammar g = new Grammar(gb);
                    sre.LoadGrammarAsync(g);
                }
                sre.RecognizeAsync(RecognizeMode.Multiple); //启动识别

                //等待结束
                while (true)
                {
                    if (stopCMD)    //手动停止
                        break;

                    //挨个组分析是否已识别完毕
                    foreach (var row in resultsList)
                    {
                        bool allGet = true;
                        foreach (var single in row)
                        {
                            if (!single)
                                allGet=false;
                        }
                        if (allGet)
                        {
                            sucessed = true;
                            break;
                        }
                    }
                    if (sucessed)
                        break;

                    //超时判定
                    TimeSpan span = DateTime.Now - timeStart;
                    if (span.TotalSeconds > timeout)
                        break;

                    DispatcherHelper.DoEvents();
                    Thread.Sleep(5);
                }

                if (sre != null)
                    sre.Dispose();
                recognizing = false;
                return sucessed;
            }
            catch (Exception ex)
            {
                if (sre != null)
                    sre.Dispose();
                recognizing = false;
                MessageBox.Show(ex.ToString());

                return false;
            }
        }


        /// <summary>
        /// 终止识别
        /// </summary>
        public void StopRecognize()
        {
            try
            {
                stopCMD = true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.ToString());
            }
        }


        /// <summary>
        /// 拆分字符串
        /// </summary>
        /// <param name="strForSplit">待拆分的字符串</param>
        private void SplitWords(string strForSplit)
        {
            try
            {
                wordsList.Clear();
                wordsList = new List<List<string>>();
                resultsList.Clear();

                string[] strArry = strForSplit.Split("/");

                foreach (string str in strArry)
                {
                    string[] strSplited = str.Split(",");
                    //删除空关键词
                    List<string> tempList = new List<string>(strSplited);
                    foreach (string tempStr in tempList)
                    {
                        if (tempStr.Length < 1)
                            tempList.Remove(tempStr);
                    }

                    if (tempList.Count > 0)
                        wordsList.Add(tempList);
                }
                //根据关键词组，初始化对应的结果bool列表
                foreach (var topItem in wordsList)
                {
                    //每个关键词对应一个bool变量，每组关键词对应一组bool
                    List<bool> tempResult = new List<bool>();
                    foreach (var word in topItem)
                        tempResult.Add(false);
                    resultsList.Add(tempResult.ToArray());
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.ToString());
            }
        }


        /// <summary>
        /// 语音识别结果解析
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            try
            {
                string txt = e.Result.Text;
                float confidence = e.Result.Confidence;
                if (confidence < 0.60) return;

                for (int row = 0; row < wordsList.Count; row++) //挨个组分析
                {
                    for (int index = 0; index < wordsList[row].Count; index++)
                    {
                        if (txt.IndexOf(wordsList[row][index]) >= 0)
                            resultsList[row][index] = true;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.ToString());
            }
        }

        #endregion


        #region 文字合成播放相关

        /// <summary>
        /// 文字合成语音播放器
        /// </summary>

        private static SpeechSynthesizer speaker = new SpeechSynthesizer();


        /// <summary>
        /// 用语音播放文字
        /// </summary>
        /// <param name="info">需要播放的字符串</param>
        /// <returns>true成功，false失败</returns>
        /// <remarks>字符串为空时返回false</remarks>
        public bool Speak(string info)
        {
            try
            {
                if (string.IsNullOrEmpty(info))
                    return false;

                Task task = new Task(() => {
                    speaker.SetOutputToDefaultAudioDevice();
                    speaker.Speak(info);
                });
                task.Start();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return false;
            }
        }

        #endregion


        #region 播放音频文件

        /// <summary>
        /// 用SoundPlayer播放音频文件（wav或mp3格式）
        /// </summary>
        /// <param name="file">音频文件路径</param>
        public void PlaySoundFile(string file)
        {
            try
            {
                Task task = new Task(() => {
                    SoundPlayer player = new SoundPlayer();
                    player.SoundLocation = file;
                    player.Load(); //同步加载声音
                    player.Play(); //启用新线程播放
                });
                task.Start();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.ToString());
            }
        }

        #endregion
    }

    /// <summary>
    /// 异步刷新界面
    /// </summary>
    public static class DispatcherHelper
    {
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static void DoEvents()
        {
            DispatcherFrame frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrames), frame);
            try { Dispatcher.PushFrame(frame); }
            catch (InvalidOperationException) { }
        }
        private static object ExitFrames(object frame)
        {
            ((DispatcherFrame)frame).Continue = false;
            return null;
        }
    }
}